#include "hplctimeprogrampage.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include "hplctimeprogramtabledelegate.h"
#include <QDebug>
#include "modulemanager.h"
#include "modulehplctimeprogram.h"
#include "modulehplctimeprogramconfigiddefine.h"
#include "modulehplctimeprogramparamiddefine.h"
#include "hplcinjectprogrampage.h"

#include <QtCharts>
#include <QPointF>

HplcTimeProgramPage::HplcTimeProgramPage(QWidget *parent)
    : QWidget(parent)
{
    setWindowTitle(tr("Hplc Time Program Page"));
    setAttribute(Qt::WA_DeleteOnClose);

    ModuleHplcTimeProgram *module = static_cast<ModuleHplcTimeProgram*>(moduleManager->find(ModuleID_HPLC_TimeProgram));
    if (module == nullptr)
        return;

    connect(module, &ModuleHplcTimeProgram::injectProgramFinished, this, [=](){
        qDebug() << "inject program finished";
        m_lbStatus->setText(tr("Running-Inject Program Finished"));
    });
    connect(module, &ModuleHplcTimeProgram::rowChanged, this, [=](int row){
        qDebug() << "row changed " << row;
        QStandardItemModel &model = m_tableView->getModel();
        m_tableView->setCurrentIndex(model.index(row, 0));
        m_tableView->setFocus();

        m_lbCurrentRow->setText(QString::number(row));
    });
    connect(module, &ModuleHplcTimeProgram::loopTimesChanged, this, [=](int loopTimes){
        qDebug() << "loop times changed " << loopTimes;
        m_loopTimes = loopTimes;
        m_leLoopTimes->setText(QString::number(loopTimes));
    });
    connect(module, &ModuleHplcTimeProgram::timeProgramFinished, this, [=](){
        qDebug() << "time program finished";

        m_lbStatus->setText(tr("Running-Time Program Finished"));
    });
    connect(module, &ModuleHplcTimeProgram::sampleTimeout, this, [=](){
        qDebug() << "sample timeout";
        m_lbStatus->setText(tr("Running-Sample Timeout"));
    });
    connect(module, &ModuleHplcTimeProgram::totalRunTimeout, this, [=](){
        qDebug() << "total run timeout";
        m_lbStatus->setText(tr("Stop-Total Run Timeout"));
    });
    qRegisterMetaType<PumpUnit>("PumpUnit");
    connect(module, &ModuleHplcTimeProgram::statusChanged, this, [=](PumpUnit status){
//        qDebug() << "Status Changed";
        m_lbCurrentPumpAFlow->setText(QString::number(status.flow * status.percent[0] / 100.0));
        m_lbCurrentPumpBFlow->setText(QString::number(status.flow * status.percent[1] / 100.0));
        m_lbCurrentPumpCFlow->setText(QString::number(status.flow * status.percent[2] / 100.0));
        m_lbCurrentPumpDFlow->setText(QString::number(status.flow * status.percent[3] / 100.0));
    });

    m_rangeList.clear();
    m_rangeList << tr("");
    m_rangeList << tr("0.0001");
    m_rangeList << tr("0.0002");
    m_rangeList << tr("0.0005");
    m_rangeList << tr("0.001");
    m_rangeList << tr("0.002");
    m_rangeList << tr("0.005");
    m_rangeList << tr("0.01");
    m_rangeList << tr("0.02");
    m_rangeList << tr("0.05");
    m_rangeList << tr("0.1");
    m_rangeList << tr("0.2");
    m_rangeList << tr("0.5");
    m_rangeList << tr("1.0");
    m_rangeList << tr("2.0");
    m_rangeList << tr("5.0");
    m_rangeList << tr("10.0");

    m_isZeroList.clear();
    m_isZeroList << tr("");
    m_isZeroList << tr("Yes");

    m_tableView = new TableViewEx(this);
    m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_tableView->setSelectionMode(QAbstractItemView::SingleSelection);
//    m_tableView->setSortingEnabled(true); // 不能排序
    QStringList headers;
    headers << tr("time(min)")
            << tr("rate(ml/min)")
            << tr("A(%)")
            << tr("B(%)")
            << tr("C(%)")
            << tr("D(%)")
            << tr("wave")
            << tr("wave2")
            << tr("zero")
            << tr("range");
    m_tableView->setHeaders(headers);
    m_tableView->setItemDelegate(new HplcTimeProgramTableDelegate(m_tableView));

    QStandardItemModel &model = m_tableView->getModel();

    // 初始化
    {
        QList<TimeProgramUnit> list;
        TimeProgramUnit unit;

        unit.pump.time = 0;
        unit.pump.flow = 1;
        unit.pump.percent[0] = 0;
        unit.pump.percent[1] = 100;
        unit.pump.percent[2] = 0;
        unit.pump.percent[3] = 0;
        unit.detector.wave = 254;
        unit.detector.wave2 = 220;
        unit.detector.isZero = 1;
        unit.detector.range = 13;
        list << unit;

        unit.pump.time = 0.1 * 60;
        unit.pump.flow = 1;
        unit.pump.percent[0] = 100;
        unit.pump.percent[1] = 0;
        unit.pump.percent[2] = 0;
        unit.pump.percent[3] = 0;
        unit.detector.wave = 254;
        unit.detector.wave2 = 220;
        unit.detector.isZero = 0;
        unit.detector.range = 0;
        list << unit;

        unit.pump.time = 0.2 * 60;
        unit.pump.flow = 1;
        unit.pump.percent[0] = 0;
        unit.pump.percent[1] = 100;
        unit.pump.percent[2] = 0;
        unit.pump.percent[3] = 0;
        unit.detector.wave = 254;
        unit.detector.wave2 = 220;
        unit.detector.isZero = 0;
        unit.detector.range = 0;
        list << unit;

        QVariant var;
        var.setValue(list);
        module->setParam(ModuleHplcTimeProgramParamID_TimeProgram, var);


        var.setValue(1);
        module->setParam(ModuleHplcTimeProgramParamID_LoopTimes, var);

        var.setValue(0.3 * 60);
        module->setParam(ModuleHplcTimeProgramParamID_SampleTime, var);

        var.setValue(0.4 * 60);
        module->setParam(ModuleHplcTimeProgramParamID_TotalRunTime, var);

        var.setValue(0.1 * 60);
        module->setParam(ModuleHplcTimeProgramParamID_InjectTime, var);
    }

    QVariant var;
    module->getParam(ModuleHplcTimeProgramParamID_TimeProgram, var);
    QList<TimeProgramUnit> pros = var.value<QList<TimeProgramUnit>>();
    for (int i = 0; i < pros.size(); i++)
    {
        QList<QStandardItem*> list;
        model.appendRow(list);

        model.setData(model.index(i, 0), pros.at(i).pump.time / 60);
        model.setData(model.index(i, 1), pros.at(i).pump.flow);
        model.setData(model.index(i, 2), pros.at(i).pump.percent[0]);
        model.setData(model.index(i, 3), pros.at(i).pump.percent[1]);
        model.setData(model.index(i, 4), pros.at(i).pump.percent[2]);
        model.setData(model.index(i, 5), pros.at(i).pump.percent[3]);

        model.setData(model.index(i, 6), pros.at(i).detector.wave);
        model.setData(model.index(i, 7), pros.at(i).detector.wave2);
        model.setData(model.index(i, 8), zero2String(pros.at(i).detector.isZero));
        model.setData(model.index(i, 9), range2String(pros.at(i).detector.range));

        model.submit();
    }

    m_ckbUsedTimeProgram = new QCheckBox(tr("UsedTimeProgram"));
    module->getParam(ModuleHplcTimeProgramParamID_UsedTimeProgram, var);
    m_isUsedTimeProgram = var.toBool();
    m_ckbUsedTimeProgram->setChecked(m_isUsedTimeProgram);
    connect(m_ckbUsedTimeProgram, &QCheckBox::stateChanged, this, [=](int state){
        if (m_isUsedTimeProgram != state)
        {
            m_isUsedTimeProgram = state;
            QVariant var;
            var.setValue(state);
            module->setParam(ModuleHplcTimeProgramParamID_UsedTimeProgram, var);
        }
    });

    // loop times
    m_lbLoopTimes = new QLabel(tr("LoopTimes"));
    m_leLoopTimes = new QLineEdit();
    module->getParam(ModuleHplcTimeProgramParamID_LoopTimes, var);
    m_loopTimes = var.toInt();
    m_leLoopTimes->setText(QString::number(m_loopTimes));
    connect(m_leLoopTimes, &QLineEdit::editingFinished, this, [=](){
        int times = m_leLoopTimes->text().toInt();
        if (m_loopTimes != times)
        {
            m_loopTimes = times;
            QVariant var;
            var.setValue(times);
            module->setParam(ModuleHplcTimeProgramParamID_LoopTimes, var);
        }
    });
    // sample time
    m_lbSampleTime = new QLabel(tr("SampleTime(min)"));
    m_leSampleTime = new QLineEdit();
    module->getParam(ModuleHplcTimeProgramParamID_SampleTime, var);
    m_sampleTime = var.toDouble() / 60;
    m_leSampleTime->setText(QString::number(m_sampleTime));
    connect(m_leSampleTime, &QLineEdit::editingFinished, this, [=](){
        double time = m_leSampleTime->text().toDouble() * 60;
        if (m_sampleTime != time)
        {
            m_sampleTime = time;
            QVariant var;
            var.setValue(time);
            module->setParam(ModuleHplcTimeProgramParamID_SampleTime, var);
        }
    });
    // total run time
    m_lbTotalRunTime = new QLabel(tr("TotalRunTime(min)"));
    m_leTotalRunTime = new QLineEdit();
    module->getParam(ModuleHplcTimeProgramParamID_TotalRunTime, var);
    m_totalRunTime = var.toDouble() / 60;
    m_leTotalRunTime->setText(QString::number(m_totalRunTime));
    connect(m_leTotalRunTime, &QLineEdit::editingFinished, this, [=](){
        double time = m_leTotalRunTime->text().toDouble() * 60;
        if (m_totalRunTime != time)
        {
            m_totalRunTime = time;
            QVariant var;
            var.setValue(time);
            module->setParam(ModuleHplcTimeProgramParamID_TotalRunTime, var);
        }
    });
    //
    m_pbStopAllPumps = new QPushButton(tr("StopAllPumps"));
    connect(m_pbStopAllPumps, &QPushButton::clicked, this, [=](){
        QVariant var;
        var.setValue(false);
        module->setConfig(ModuleHplcTimeProgramConfigID_StartStopAllPumps, var);
    });
    m_pbInjectProgram = new QPushButton(tr("InjectProgram"));
    connect(m_pbInjectProgram, &QPushButton::clicked, this, [=](){
        HplcInjectProgramPage *page = new HplcInjectProgramPage();

        QVariant var;
        module->getConfig(ModuleHplcTimeProgramConfigID_Start, var);
        page->setRunning(var.toBool());

        module->getParam(ModuleHplcTimeProgramParamID_InjectFlow, var);
        double flow = var.toDouble();
        module->getParam(ModuleHplcTimeProgramParamID_InjectTime, var);
        double time = var.toDouble() / 60;
        page->setParam(flow, time);

        connect(page, &HplcInjectProgramPage::flowChanged, this, [=](double flow){
            QVariant var;
            var.setValue(flow);
            module->setParam(ModuleHplcTimeProgramParamID_InjectFlow, var);
            qDebug() << "set inject flow" << flow;
        });
        connect(page, &HplcInjectProgramPage::timeChanged, this, [=](double time){
            QVariant var;
            var.setValue(time * 60);
            module->setParam(ModuleHplcTimeProgramParamID_InjectTime, var);
            qDebug() << "set inject time" << time;
        });
        connect(page, &HplcInjectProgramPage::requestStart, this, [=](){
            QVariant var;
            var.setValue(true);
            module->setConfig(ModuleHplcTimeProgramConfigID_StartInjectProgram, var);
            qDebug() << "start inject program";

            m_lbStatus->setText(tr("Running-Inject Program..."));
        });

        page->show();
    });
    m_pbGradientCurve = new QPushButton(tr("GradientCurve"));
    connect(m_pbGradientCurve, &QPushButton::clicked, this, &HplcTimeProgramPage::onShowGradientCurve);

    QVBoxLayout *vblRight = new QVBoxLayout();
    vblRight->addWidget(m_ckbUsedTimeProgram);
    vblRight->addWidget(m_lbLoopTimes);
    vblRight->addWidget(m_leLoopTimes);
    vblRight->addWidget(m_lbSampleTime);
    vblRight->addWidget(m_leSampleTime);
    vblRight->addWidget(m_lbTotalRunTime);
    vblRight->addWidget(m_leTotalRunTime);
    vblRight->addWidget(m_pbStopAllPumps);
    vblRight->addWidget(m_pbInjectProgram);
    vblRight->addWidget(m_pbGradientCurve);

    m_pbTest = new QPushButton(tr("Test"));
    connect(m_pbTest, &QPushButton::clicked, this, [&model](){
        for (int i = 0; i < model.rowCount(); i++)
        {
            QStringList list;
            for (int j = 0; j < model.columnCount(); j++)
            {
                QString str = model.data(model.index(i, j), Qt::DisplayRole).toString();
                list << str;
            }
            qDebug() << list;
        }
    });
    m_pbRun = new QPushButton(tr("Run"));
    connect(m_pbRun, &QPushButton::clicked, this, [=](){
        QVariant var;
        module->setConfig(ModuleHplcTimeProgramConfigID_Start, var);
        qDebug() << "start";
        m_lbStatus->setText(tr("Running-Time Program..."));
    });
    m_pbRunFirstRow = new QPushButton(tr("RunFirstRow"));
    connect(m_pbRunFirstRow, &QPushButton::clicked, this, [=](){
        QVariant var;
        module->setConfig(ModuleHplcTimeProgramConfigID_StartFirstLine, var);
        qDebug() << "start first row";
        m_lbStatus->setText(tr("Running-First Row..."));
    });
    m_pbRunBasicParam = new QPushButton(tr("RunBasicParam"));
    connect(m_pbRunBasicParam, &QPushButton::clicked, this, [=](){
        QVariant var;
        module->setConfig(ModuleHplcTimeProgramConfigID_StartBasicParam, var);
        qDebug() << "start basic param";
        m_lbStatus->setText(tr("Running-Basic Param..."));
    });
    m_pbPauseRestore = new QPushButton(tr("Pause"));
    connect(m_pbPauseRestore, &QPushButton::clicked, this, [=](){
        QVariant var;
        module->getConfig(ModuleHplcTimeProgramConfigID_Pause, var);
        if (!var.toBool())
        {
            module->setConfig(ModuleHplcTimeProgramConfigID_Pause, var);
            m_pbPauseRestore->setText(tr("Restore"));
            qDebug() << "pause";
            m_lbStatus->setText(tr("Pause"));
        }
        else
        {
            module->setConfig(ModuleHplcTimeProgramConfigID_Restore, var);
            m_pbPauseRestore->setText(tr("Pause"));
            qDebug() << "restore";
            m_lbStatus->setText(tr("Restore"));
        }
    });
    m_pbStop = new QPushButton(tr("Stop"));
    connect(m_pbStop, &QPushButton::clicked, this, [=](){
        QVariant var;
        module->setConfig(ModuleHplcTimeProgramConfigID_Stop, var);
        qDebug() << "stop";
        m_lbStatus->setText(tr("Stop"));
    });
    QHBoxLayout *hblBottom = new QHBoxLayout();
    hblBottom->addWidget(m_pbTest);
    hblBottom->addWidget(m_pbRun);
    hblBottom->addWidget(m_pbRunFirstRow);
    hblBottom->addWidget(m_pbRunBasicParam);
    hblBottom->addWidget(m_pbPauseRestore);
    hblBottom->addWidget(m_pbStop);

    m_lbCurrent = new QLabel(tr("Current"));
    m_lbStatus = new QLabel(tr("---"));
    m_lbCurrentRow = new QLabel();
    m_lbCurrentPumpAFlow = new QLabel();
    m_lbCurrentPumpBFlow = new QLabel();
    m_lbCurrentPumpCFlow = new QLabel();
    m_lbCurrentPumpDFlow = new QLabel();

    QHBoxLayout *hblStatus = new QHBoxLayout();
    hblStatus->addWidget(m_lbCurrent);
    hblStatus->addWidget(m_lbStatus);
    hblStatus->addWidget(m_lbCurrentRow);
    hblStatus->addWidget(m_lbCurrentPumpAFlow);
    hblStatus->addWidget(m_lbCurrentPumpBFlow);
    hblStatus->addWidget(m_lbCurrentPumpCFlow);
    hblStatus->addWidget(m_lbCurrentPumpDFlow);

    QHBoxLayout *hbl = new QHBoxLayout();
    hbl->addWidget(m_tableView, 8);
    hbl->addLayout(vblRight, 1);

    QVBoxLayout *vbl = new QVBoxLayout();
    vbl->addLayout(hbl);
    vbl->addLayout(hblBottom);
    vbl->addLayout(hblStatus);
    setLayout(vbl);
}

HplcTimeProgramPage::~HplcTimeProgramPage()
{

}

TimeProgramUnit HplcTimeProgramPage::getTableRow(int row)
{
    TimeProgramUnit unit;
    QStandardItemModel &model = m_tableView->getModel();

    unit.pump.time = model.data(model.index(row, 0), Qt::DisplayRole).toDouble() * 60;
    unit.pump.flow = model.data(model.index(row, 1), Qt::DisplayRole).toDouble();
    unit.pump.percent[0] = model.data(model.index(row, 2), Qt::DisplayRole).toUInt();
    unit.pump.percent[1] = model.data(model.index(row, 3), Qt::DisplayRole).toUInt();
    unit.pump.percent[2] = model.data(model.index(row, 4), Qt::DisplayRole).toUInt();
    unit.pump.percent[3] = model.data(model.index(row, 5), Qt::DisplayRole).toUInt();

    unit.detector.wave = model.data(model.index(row, 6), Qt::DisplayRole).toUInt();
    unit.detector.wave2 = model.data(model.index(row, 7), Qt::DisplayRole).toUInt();
    unit.detector.isZero = string2Zero(model.data(model.index(row, 8), Qt::DisplayRole).toString());
    unit.detector.range = string2Range(model.data(model.index(row, 9), Qt::DisplayRole).toString());

    return unit;
}

QList<TimeProgramUnit> HplcTimeProgramPage::getTable()
{
    TimeProgramUnit unit;
    QList<TimeProgramUnit> units;
    units.clear();
    QStandardItemModel &model = m_tableView->getModel();
    for (int i = 0; i < model.rowCount(); i++)
    {
        unit = getTableRow(i);
        units << unit;
    }
    return units;
}

QString HplcTimeProgramPage::zero2String(bool isZero)
{
    if (isZero)
        return tr("Yes");
    else
        return tr("");
}

bool HplcTimeProgramPage::string2Zero(QString str)
{
    if (str == tr("Yes"))
        return true;
    else
        return false;
}

QString HplcTimeProgramPage::range2String(quint8 range)
{
    switch (range)
    {
        case 0:
            return tr("");
        case 1:
            return tr("0.0001");
        case 2:
            return tr("0.0002");
        case 3:
            return tr("0.0005");
        case 4:
            return tr("0.001");
        case 5:
            return tr("0.002");
        case 6:
            return tr("0.005");
        case 7:
            return tr("0.01");
        case 8:
            return tr("0.02");
        case 9:
            return tr("0.05");
        case 10:
            return tr("0.1");
        case 11:
            return tr("0.2");
        case 12:
            return tr("0.5");
        case 13:
            return tr("1.0");
        case 14:
            return tr("2.0");
        case 15:
            return tr("5.0");
        case 16:
            return tr("10.0");
        default:
            return tr("");
    }
}

quint8 HplcTimeProgramPage::string2Range(QString str)
{
    if (str == tr(""))
        return 0;
    else if (str == tr("0.0001"))
        return 1;
    else if (str == tr("0.0002"))
        return 2;
    else if (str == tr("0.0005"))
        return 3;
    else if (str == tr("0.001"))
        return 4;
    else if (str == tr("0.002"))
        return 5;
    else if (str == tr("0.005"))
        return 6;
    else if (str == tr("0.01"))
        return 7;
    else if (str == tr("0.02"))
        return 8;
    else if (str == tr("0.05"))
        return 9;
    else if (str == tr("0.1"))
        return 10;
    else if (str == tr("0.2"))
        return 11;
    else if (str == tr("0.5"))
        return 12;
    else if (str == tr("1.0"))
        return 13;
    else if (str == tr("2.0"))
        return 14;
    else if (str == tr("5.0"))
        return 15;
    else if (str == tr("10.0"))
        return 16;
    else
        return 0;
}

void HplcTimeProgramPage::onShowGradientCurve()
{
    //![1]
    QChart *chart = new QChart();
    //chart->legend()->hide();
    //chart->legend()->
    //chart->setTitle("Multiaxis chart example");
    //![1]

    //![2]
    //QValueAxis *axisX = new QValueAxis;
    ////axisX->setTickCount(10);
    //chart->addAxis(axisX, Qt::AlignBottom);
    //![2]

    //![3]
    QLineSeries *series = new QLineSeries; //QSplineSeries
    QLineSeries *series2 = new QLineSeries;
    QLineSeries *series3 = new QLineSeries;
    QLineSeries *series4 = new QLineSeries;
    //*series << QPointF(1, 5) << QPointF(3.5, 18) << QPointF(4.8, 7.5) << QPointF(10, 2.5);
    //chart->addSeries(series);


    QList<TimeProgramUnit> table = getTable();
    double maxFlow = 0;
    foreach (auto l, table)
    {
        double pumpAFlow = l.pump.flow * l.pump.percent[0] / 100.0;
        double pumpBFlow = l.pump.flow * l.pump.percent[1] / 100.0;
        double pumpCFlow = l.pump.flow * l.pump.percent[2] / 100.0;
        double pumpDFlow = l.pump.flow * l.pump.percent[3] / 100.0;

        if (l.pump.flow > maxFlow)
            maxFlow = l.pump.flow;

        *series << QPointF(l.pump.time, pumpAFlow);
        *series2 << QPointF(l.pump.time, pumpBFlow);
        *series3 << QPointF(l.pump.time, pumpCFlow);
        *series4 << QPointF(l.pump.time, pumpDFlow);
    }
    series->setName("A");
    series2->setName("B");
    series3->setName("C");
    series4->setName("D");
    chart->addSeries(series);
    chart->addSeries(series2);
    chart->addSeries(series3);
    chart->addSeries(series4);

    chart->createDefaultAxes();
    chart->axes(Qt::Horizontal).first()->setRange(0, table.last().pump.time);
    chart->axes(Qt::Vertical).first()->setRange(0, maxFlow);

    //QValueAxis *axisY = new QValueAxis;
    ////axisY->setLinePenColor(series->pen().color());

    //chart->addAxis(axisY, Qt::AlignLeft);
    //series->attachAxis(axisX);
    //series->attachAxis(axisY);
    //![3]

    ////![4]
    //series = new QSplineSeries;
    //*series << QPointF(1, 0.5) << QPointF(1.5, 4.5) << QPointF(2.4, 2.5) << QPointF(4.3, 12.5)
    //	<< QPointF(5.2, 3.5) << QPointF(7.4, 16.5) << QPointF(8.3, 7.5) << QPointF(10, 17);
    //chart->addSeries(series);

    //QCategoryAxis *axisY3 = new QCategoryAxis;
    //axisY3->append("Low", 5);
    //axisY3->append("Medium", 12);
    //axisY3->append("High", 17);
    //axisY3->setLinePenColor(series->pen().color());
    //axisY3->setGridLinePen((series->pen()));

    //chart->addAxis(axisY3, Qt::AlignRight);
    //series->attachAxis(axisX);
    //series->attachAxis(axisY3);
    //![4]

    //![5]
    QChartView *chartView = new QChartView(chart);
    chartView->setRenderHint(QPainter::Antialiasing);
    chartView->show();
}
